package com.itliuhouse.success.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.itliuhouse.success.domain.dto.PageDTO;
import com.itliuhouse.success.domain.query.UserQuery;
import com.itliuhouse.success.domain.vo.AddressVO;
import com.itliuhouse.success.domain.vo.UserVO;
import com.itliuhouse.success.enums.UserStatus;
import com.itliuhouse.success.mapper.UserMapper;
import com.itliuhouse.success.pojo.Address;
import com.itliuhouse.success.pojo.User;
import com.itliuhouse.success.service.UserService;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper , User> implements UserService {
    @Override
    public void deductBalance(Long id, Integer money) {
        //这个是带有业务逻辑的一件事情,不能简单处理
        //所以这个时候需要再service层进行调用
        //1.查询用户
        User user = getById(id);
        //2.判断用户状态
        if(user == null || user.getStatus() == UserStatus.FREEZE){
            throw new RuntimeException("用户状态异常");
        }
        //3.查询用户余额
        if(user.getBalance() < money){
            throw new RuntimeException("用户余额不足");
        }
        //4.扣减余额 需要在mapper中去实现
//        baseMapper.deductMoneyById(id , money);
        //计算余额
        int remainBalance = user.getBalance() - money;
        lambdaUpdate()
                .set(User::getBalance , remainBalance)
                .set(remainBalance == 0 , User::getStatus , UserStatus.FREEZE)//动态判断,是否更新status
                .eq(User::getId , id)
                .eq(User::getBalance , user.getBalance())//乐观锁
                .update();

    }

    @Override
    public UserVO queryUserAndAddressById(Integer id) {
        //1.查询用户信息
        User user = getById(id);
        if(user == null){
            return null;
        }
        //2.查询收货地址
        //这里有两种方式查询收货地址  1注入AddressService来进行实现   2.直接使用Db类进行实现
        List<Address> addressList = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();
        //3.处理vo,因为这里需要的是AddressVO 所以 这里要把Address 专抓为AddressVO
        List<AddressVO> addressVOS = BeanUtil.copyToList(addressList, AddressVO.class);
        //将User对象转化为UserVO
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        userVO.setAddresses(addressVOS);
        return userVO;
    }

    @Override
    public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
        //1.查询用户
        List<User> users = this.listByIds(ids);
        //如果用户的数据为空  就返回一个空集合
        if(CollUtil.isEmpty(users)){
            return Collections.emptyList();
        }
        //2.查询地址
        //2.1获取哦用户id的集合
        // 获取users对象的流,取出id 最后转换成集合 等会学习一下 stream  这个功能很强大
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        System.out.println(userIds);
        //2.2 根据用户id查询地址 , 因为我们是查询地址 所以 我们一定需要一个地址的Pojo 这样才能通过反射去查找到数据库信息
        List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();
        //2.3 将地址转化为地址的VO,因为后面给用户添加地址的时候需要的是地址的VO
        List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);
        //定义AddressVO的集合
        Map<Long , List<AddressVO>> addressMap = new HashMap<>();
        if(CollUtil.isNotEmpty(addressVOList)){
            addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        }
        System.out.println(addressMap);
        //3.转换User为UserVO
        ArrayList<UserVO> list = new ArrayList<UserVO>(users.size());
        for (User user : users){
            //3.1 转换User对象为UserVo  为什么呢  因为数据返回要求的是UserVO  比较复杂
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            //添加地址
            //两种方式 1，直接在循环里面查找 然后添加进去  ，效率比较低  2.直接在外部一次查询出来,然后直接使用即可
            //我们这里选择第二种方式
            userVO.setAddresses(addressMap.get(user.getId()));
            list.add(userVO);
        }

        return list;
    }

    @Override
    public PageDTO<UserVO> queryUsersPage(UserQuery query) {
        String name = query.getName();
        Integer status = query.getStatus();
//        //1.分页条件
//        Page<User> page = Page.of(query.getPageNo(), query.getPageSize());
//        if(query.getSortBy() != null){
//            //按照客户端传递过来的条件进行排序
//            OrderItem orderItem = new OrderItem();
//            orderItem.setColumn(query.getSortBy()).setAsc(query.getIsAsc());
//            page.addOrder(orderItem);
//        }else{
//            //默认按照更新时间进行排序
//            OrderItem orderItem1 = new OrderItem();
//            orderItem1.setColumn("update_time").setAsc(false);
//            page.addOrder(orderItem1);
//        }

        //以上的条件可以简化成下面的一句话
        Page<User> page = query.toMpPageDefaultSortByCreateTimeDesc();

        //2.进行查询
        QueryWrapper<User> wrapper = new QueryWrapper<User>().like(name != null, "username", name)
                .eq(status != null, "status", status);
        Page<User> page_info = page(page , wrapper);
        //3.数据非空校验
        //获取数据记录

//        List<User> records = page_info.getRecords();
//        if(records == null || records.size() <= 0){
//            //无数据,返回空结果 我知道 这样不能直接使用  因为data方法  只是set  和  get的方法
//            //而无参构造和有参构造都会有对应的注解
//            return new PageDTO<>(page_info.getTotal() , page_info.getPages() , Collections.emptyList());
//        }
//        //有数据 进行转化
//        List<UserVO> voList = BeanUtil.copyToList(records, UserVO.class);
//        //封装返回
//        PageDTO<UserVO> pageDTO = new PageDTO<>(page_info.getTotal(), page_info.getPages(), voList);
//        return pageDTO;
        return PageDTO.of(page_info , UserVO.class);
    }


    //使用自定义PO到VO的转换过程  可以这样做
    @Override
    public PageDTO<UserVO> queryUsersByPage(UserQuery query) {
        //1.构建条件
        Page<User> page = query.toMpPageDefaultSortByCreateTimeDesc();
        //2.查询
        Page<User> page_new = page(page);
        //3.返回封装 其实还是因为我不懂 lambda表达式  所以 才会这样  现在先实现目标  先会使用 后面在学
        return PageDTO.of(page_new , user -> {
            //可以看出来 user 其实就是user对象 代表处理的是前面的page_new 的 user对象
            //拷贝属性到VO
            UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
            //用户名脱敏
            String username = vo.getUsername();
            //对用户名进行二次处理  然后 重新设置到对象中
            vo.setUsername(username.substring(0 , username.length() - 2) + "**");
            return vo;
        });


    }
}
